package junit;

import org.junit.runner.Description;
import org.junit.runner.notification.Failure;

import java.io.*;
import java.util.*;

class TestStatistics{
    Set<String> failedRecently;
    Map<String, Long> durations;

    public TestStatistics(Set<String> failedRecently, Map<String, Long> durations) {
        this.failedRecently = failedRecently;
        this.durations = durations;
    }

    public TestStatistics() {
        failedRecently = new HashSet<String>();
        durations = new HashMap<String, Long>();
    }

    static TestStatistics loadFromFile(String statistcsFileName){
        ObjectInputStream input = null;
        try {
            input = new ObjectInputStream(new FileInputStream(statistcsFileName));
            return (TestStatistics) input.readObject();
        } catch (Exception e) {
            System.err.println("Failed to load .failed-tests");
        }finally{
            tryToClose(input);
        }
        return new TestStatistics(new HashSet<String>(), new HashMap<String, Long>());

    }

    private static void tryToClose(ObjectInputStream input) {
        try {
            input.close();
        } catch (IOException e) {
            System.err.println("Can not close .failed-tests");
        }
    }

    Comparator<Description> comparator(){
        return new Comparator<Description>() {
            public int compare(Description o1, Description o2) {
                String className1 = FlexibleSuite.className(o1);
                String className2 = FlexibleSuite.className(o2);
                if (failedRecently.contains(className1) && !failedRecently.contains(className2)) return -1;
                if (failedRecently.contains(className2) && !failedRecently.contains(className1)) return 1;
                Long duration1 = durations.containsKey(className1) ? durations.get(className1) : 0;
                Long duration2 = durations.containsKey(className2) ? durations.get(className2) : 0;
                return duration1.compareTo(duration2);
            }
        };
    }

    public void saveTo(String fileName) {
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
            out.writeObject(this);
            out.close();
        } catch (IOException e) {
            System.err.println("Can not write file .failed-classes; "+e.getMessage());
        }
    }

    public void add(Failure failure) {
        failedRecently.add(FlexibleSuite.className(failure.getDescription()));
    }

    public void addTestDuration(String className, long duration) {
        long previous = 0;
        if (durations.containsKey(className)) previous = durations.get(className);
        durations.put(className, duration + previous);
    }

    Map<String,Long> durations() {
        return durations;
    }

    public boolean hasErrors() {
        return failedRecently.isEmpty();
    }

    Set<String> failedTestClasses() {
        return failedRecently;
    }

    void printReport() {
        if (!hasErrors()){
            System.err.println("Failures : "+ failedTestClasses().toString());
        }
        System.out.println("Test Statistics : \n"+ durations().toString().replace(",", "\n\t"));
    }
}
